package ru.ifmo.thesis.util;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;

import javax.activation.FileDataSource;

import org.apache.xmlbeans.impl.xb.ltgfmt.TestCase.Files;
import org.jgap.Gene;
import org.jgap.IChromosome;

import ru.ifmo.thesis.domain.GeoServiceFactory;
import ru.ifmo.thesis.domain.Job;
import ru.ifmo.thesis.domain.Location;
import ru.ifmo.thesis.domain.Shedule;
import ru.ifmo.thesis.domain.Worker;
import ru.ifmo.thesis.gp.WorkPlanGene;
import ru.ifmo.thesis.quantities.Minutes;
import ru.ifmo.thesis.solver.DirectSolver;

public class Algorithms {

	public static double calculateSheduleCost(Shedule shedule) {
		double result = 0;
		for (Worker w : shedule.getWorkers()) {
			double interSumm = 0;
			int waiting = 0;
			Location prevLoc = GeoServiceFactory.getGeoService().getOfficeLocation();
			for (Job t : shedule.getPersonalShedule(w)) {
				//geo time
				waiting += (int) Math.round(Algorithms.MINUTES_IN_HOUR * GeoServiceFactory.getGeoService().distance(
						prevLoc, t.getLocation()).value() / DirectSolver.SPEED);
				//time on elemination
				waiting += t.getExpectedEliminationTime().value();
				
			    interSumm += t.getContractOptions().getPenaltyFunction().calculatePenalty(new Minutes(waiting));
			    prevLoc = t.getLocation();
			}
			result += interSumm;
		}
		return result;
	}
	
	private static final int MINUTES_IN_HOUR = 60;

	public static Shedule constructShedule(IChromosome chromosome) {
		Shedule shedule = new Shedule();
		for (Gene workerTasks : chromosome.getGenes()) {
			WorkPlanGene myGene = (WorkPlanGene) workerTasks;
			Worker w = myGene.getAssociatedWorker();
			
			@SuppressWarnings("unchecked")
			ArrayList<Job> jobList = (ArrayList<Job>) myGene.getAllele();
			
			for (Job t : jobList) {
				shedule.appendJob(w, t);
			}
		}
		return shedule;
	}

	public static List<Double> doubleSequence(double start, double end, double interval) {
		List<Double> result = new ArrayList<Double>();
		
		result.add(start);
		double current = start;
		while (current + interval < end) {
			current += interval;
			result.add(current);
		}
		
		return result;
	}

	public static List<Integer> integerSequence(int start, int end, int interval) {
		List<Integer> result = new ArrayList<Integer>();
		
		result.add(start);
		int current = start;
		while (current + interval < end) {
			current += interval;
			result.add(current);
		}
		
		return result;
	}

	public static void backup(File f) {
		String path = f.getAbsolutePath();
		
		for (int i = 0; i < Integer.MAX_VALUE; i++) {
			String copyName = path.replace(".xslx", "(copy " + i + ").xslx");
		
			File copy = new File(copyName);
			if (!copy.exists()) {
				try {
					copy(f, copy);
				} catch (IOException e) {
					throw new RuntimeException(e);
				}
				return;
			}
		}
		
		throw new RuntimeException("Too many backups! Delete ones.");
	}

	private static void copy(File f, File copy) throws IOException {
		InputStream iStream = new BufferedInputStream(new FileInputStream(f));
		OutputStream oStream = new BufferedOutputStream(new FileOutputStream(copy));
		
		byte[] buf = new byte[5 * 1024 * 1024];
		int readBytes = 0;
		while ((readBytes = iStream.read(buf)) > 0) {
			oStream.write(buf, 0, readBytes);
		}
		
		iStream.close();
		oStream.close();
	}
	
}
